home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Magazin/MacEasy 19
/
Mac Magazin and MacEasy Magazine CD - Issue 19.iso
/
Musik & Kunst
/
Ear Workout 2.1
/
source code
/
ear_intervals.cp
< prev
next >
Wrap
Text File
|
1996-01-06
|
17KB
|
533 lines
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <OSUtils.h>
#include <QuickDraw.h>
#include <Sound.h>
#define NEED_MAC_STUFF 1
#include "Ninkasi:C++ util:generic.h"
#include "Ninkasi:C++ util:complete_window.h"
#include "ear_defines.h"
#include "ear_decl.h"
#include "ear_prototypes.h"
DEN_MOTHER_T interval_den_mother;
void choose_interval(int *note1,int *note2,
int *duration1,int *duration2,int *rest_between,
int *abs_i,int *lower_note,int *higher_note,
int max_interval,int *interval_enabled,
int mean_note,double typical_tempo,int *shorter_duration);
void
interval_den_mother(complete_window *my_complete_window)
{
//--- decoder string for controls:
static char **decoder_string;
static int have_decoder_string = 0;
//--- their score:
static int ntries = 0;
static int nright = 0;
static int nright_list[MAX_INTERVAL+1],nwrong_list[MAX_INTERVAL+1];
//--- keeping track of my current state:
static int first_time = 1;
static int they_have_interval_to_consider = 0;
static int melodic_or_harmonic = 1;
static int play_it,give_hint,type_of_hint,answer,they_did_something;
static int they_gave_answer,twiddle_radio_buttons,need_to_redraw,
twiddle_check_boxes,need_to_redraw_all,ready_to_update,
right,cleared_scores,changed_tempo;
static int current_icon = BLANK_ICON_ID;
//--- parameters that determine what intervals I play and how I play them:
#define TYPICAL_TEMPO_MELODIC 105
#define TYPICAL_TEMPO_HARMONIC 45
static double typical_tempo = TYPICAL_TEMPO_MELODIC;
static int mean_note = 66;
static int interval_enabled[MAX_INTERVAL+1];
//--- about the current interval:
static int note1,note2,duration1,duration2,rest_between,abs_i,
shorter_duration;
static int lower_note = -999;
static int higher_note = -999;
char nifty_name[100];
int nifty_index,recognized;
GrafPtr save_graf;
they_did_something = 0;
give_hint = 0;
play_it = 0;
they_gave_answer = 0;
twiddle_radio_buttons = 0;
twiddle_check_boxes = 0;
need_to_redraw = 0;
need_to_redraw_all = 0;
ready_to_update = 0;
cleared_scores = 0;
changed_tempo = 0;
if (first_time) {
first_time = 0;
for (int i=0; i<=MAX_INTERVAL; i++) {
nright_list[i] = 0;
nwrong_list[i] = 0;
interval_enabled[i] = (i!=0) && (i<=12);
}
}
if (!have_decoder_string) {
decoder_string = (char **) GetString((short) INTERVAL_DLOG_ID);
if (!VALID_HANDLE(decoder_string))
bail_out("unable to get decoder string");
HLock((char **) decoder_string);
have_decoder_string = 1;
}
switch(my_complete_window->whassup) {
case complete_window_created:
need_to_redraw = 1;
need_to_redraw_all = 1;
break;
case complete_window_redraw:
need_to_redraw = 1;
need_to_redraw_all = 1;
ready_to_update = 1; //-- main program does begin update & sets graf port
break;
case complete_window_action:
part_number_to_nifty_label(nifty_name,&nifty_index,
*decoder_string,my_complete_window->part_number);
if (nifty_index != -999) {
recognized = 0;
if (strcmp(nifty_name,"answers")==0) {
recognized = 1;
they_gave_answer = 1;
need_to_redraw = 1;
answer = nifty_index;
}
if (strcmp(nifty_name,"enabled")==0) {
twiddle_check_boxes = 1;
need_to_redraw = 1;
if (nifty_index>=0 && nifty_index<=MAX_INTERVAL)
interval_enabled[nifty_index] = !interval_enabled[nifty_index];
recognized = 1;
}
if (strcmp(nifty_name,"play_again")==0) {
recognized = 1;
play_it = 1;
}
if (strcmp(nifty_name,"fifth")==0) {
recognized = 1;
give_hint = 1;
type_of_hint = 6;
}
if (strcmp(nifty_name,"octave")==0) {
recognized = 1;
give_hint = 1;
type_of_hint = 1;
}
if (strcmp(nifty_name,"connecting_scale")==0) {
recognized = 1;
give_hint = 1;
type_of_hint = 2;
}
if (strcmp(nifty_name,"play_lower")==0) {
recognized = 1;
give_hint = 1;
type_of_hint = 3;
}
if (strcmp(nifty_name,"compare_with_another")==0) {
recognized = 1;
give_hint = 1;
type_of_hint = 4;
}
if (strcmp(nifty_name,"inv")==0) {
recognized = 1;
give_hint = 1;
type_of_hint = 5;
}
if (strcmp(nifty_name,"tempol")==0) {
int bump;
bump = typical_tempo*.05;
if (bump<1) bump = 1;
typical_tempo -= bump;
if (typical_tempo<10) typical_tempo=10;
changed_tempo = 1;
need_to_redraw = 1;
}
if (strcmp(nifty_name,"tempoh")==0) {
int bump;
bump = typical_tempo*.05;
if (bump<1) bump = 1;
typical_tempo += bump;
if (typical_tempo>300) typical_tempo=300;
changed_tempo = 1;
need_to_redraw = 1;
}
if (strcmp(nifty_name,"clear_scores")==0) {
recognized = 1;
ntries = 0;
nright = 0;
{
int i;
for (i=0; i<=MAX_INTERVAL; i++) {
nright_list[i] = 0;
nwrong_list[i] = 0;
}
}
need_to_redraw = 1;
cleared_scores = 1;
current_icon = BLANK_ICON_ID;
}
if (strcmp(nifty_name,"melodic")==0) {
melodic_or_harmonic = 1;
twiddle_radio_buttons = 1;
need_to_redraw = 1;
typical_tempo = TYPICAL_TEMPO_MELODIC;
recognized = 1;
}
if (strcmp(nifty_name,"harmonic")==0) {
melodic_or_harmonic = 2;
twiddle_radio_buttons = 1;
need_to_redraw = 1;
typical_tempo = TYPICAL_TEMPO_HARMONIC;
recognized = 1;
}
they_did_something = recognized;
}//--end if they hit a valid control
break;
case complete_window_erase:
they_have_interval_to_consider = 0;
first_time = 1;
interval_window_exists = 0;
return;
}
if (they_gave_answer) {
right = (answer == abs_i);
++ntries;
nright += right;
if (right) {
current_icon = CHECK_ICON_ID;
++nright_list[abs_i];
}
else {
current_icon = X_ICON_ID;
++nwrong_list[abs_i];
}
they_have_interval_to_consider = 0;
}
if (need_to_redraw) {
if (!ready_to_update) {
GetPort(&save_graf);
SetPort(my_complete_window->the_window);
}
if (twiddle_radio_buttons || need_to_redraw_all) {
set_ctl_by_nifty_label(my_complete_window->the_window,
"melodic",1,*decoder_string,(melodic_or_harmonic==1));
set_ctl_by_nifty_label(my_complete_window->the_window,
"harmonic",1,*decoder_string,(melodic_or_harmonic==2));
}
if (twiddle_check_boxes || need_to_redraw_all) {
for (int i=0; i<=MAX_INTERVAL; i++) {
set_ctl_by_nifty_label(my_complete_window->the_window,
"enabled",i,*decoder_string,interval_enabled[i]);
}
}
if (need_to_redraw_all) {
refresh_text(my_complete_window,"tx",1,*decoder_string);
}
if (changed_tempo || twiddle_radio_buttons || need_to_redraw_all) {
Handle h;
char s[50];
get_item_by_nifty_label(my_complete_window->the_window,
"tempo",1,*decoder_string,&h);
if (VALID_HANDLE(h)) {
sprintf(s+1,"%d",(int) typical_tempo);
s[0] = strlen(s+1);
SetIText(h,(unsigned char *) s);
}
}
if (they_gave_answer || cleared_scores || need_to_redraw_all) {
Handle h;
char s[50];
int i,tot;
get_item_by_nifty_label(my_complete_window->the_window,
"total_score",1,*decoder_string,&h);
if (VALID_HANDLE(h)) {
if (ntries>0) {
sprintf(s+1,"%d %c",(int) ((100.*nright)/((double) ntries)),'%');
s[0] = strlen(s+1);
}
else {
sprintf(s+1," ");
s[0] = strlen(s+1);
}
TextSize((short) 18);
TextFont(geneva);
SetIText(h,(unsigned char *) s);
normal_text_style();
}
get_item_by_nifty_label(my_complete_window->the_window,
"totals",1,*decoder_string,&h);
if (VALID_HANDLE(h)) {
if (ntries>0) {
sprintf(s+1,"%d / %d",(int) nright,(int) ntries);
s[0] = strlen(s+1);
}
else {
sprintf(s+1," ");
s[0] = strlen(s+1);
}
TextFont(geneva);
SetIText(h,(unsigned char *) s);
normal_text_style();
}
TextFont((short) geneva);
for (i=0; i<=MAX_INTERVAL; i++) {
tot = nright_list[i]+nwrong_list[i];
if (need_to_redraw_all || cleared_scores
|| (they_gave_answer && i==abs_i)) {
get_item_by_nifty_label(my_complete_window->the_window,
"scores",i,*decoder_string,&h);
if (VALID_HANDLE(h)) {
if (tot>0) {
sprintf(s+1,"%d / %d",(int) nright_list[i],(int) tot);
s[0] = strlen(s+1);
}
else {
sprintf(s+1," ");
s[0] = strlen(s+1);
}
SetIText(h,(unsigned char *) s);
}
}
}//-- end loop over intervals
normal_text_style();
}
if (they_gave_answer) {
int i;
if (!right) {
for (i=0; i<=MAX_INTERVAL; i++) {
if (i!=abs_i)
hide_ctl_by_nifty_label(my_complete_window->the_window,
"answers",i,*decoder_string);
}
}
}
if (they_gave_answer || cleared_scores || need_to_redraw_all) {
Handle hh;
Rect rr;
hh = GetIcon((short) current_icon);
if (VALID_HANDLE(hh)) {
get_rect_by_nifty_label(my_complete_window->the_window,
"icon",1,*decoder_string, &rr);
PlotIcon(&rr,hh);
}
}
if (they_gave_answer && !right) {
int i;
rest((int)( 2. * 2000.*60./typical_tempo));
for (i=0; i<=MAX_INTERVAL; i++) {
if (i!=abs_i)
show_ctl_by_nifty_label(my_complete_window->the_window,
"answers",i,*decoder_string);
}
}
if (!ready_to_update) {
SetPort(save_graf);
}
}//---end if need to redraw
if (!they_have_interval_to_consider) {
int previous_lower,previous_higher;
previous_lower = lower_note;
previous_higher = higher_note;
do {
choose_interval(¬e1,¬e2,&duration1,&duration2,&rest_between,
&abs_i,&lower_note,&higher_note,
MAX_INTERVAL,interval_enabled,
mean_note,typical_tempo,&shorter_duration);
} while (previous_lower==lower_note && previous_higher==higher_note);
play_it = 1;
they_have_interval_to_consider = 1;
}
if (play_it) {
int notes[4];
switch(melodic_or_harmonic) {
case 1: //-- melodic
notes[0] = note1;
play_chord(1,my_snd_chan,notes,duration1,1);
rest(rest_between);
notes[0] = note2;
play_chord(1,my_snd_chan,notes,duration2,1);
break;
case 2:
notes[0] = note1;
notes[1] = note2;
play_chord(2,my_snd_chan,notes,duration1,1);
break;
}
}
if (give_hint) {
int notes[4];
switch(type_of_hint) {
case 1: //-- play octave
notes[0] = lower_note;
play_chord(1,my_snd_chan,notes,shorter_duration,1);
notes[0] = lower_note+12;
play_chord(1,my_snd_chan,notes,shorter_duration,1);
break;
case 2: //-- play connecting scale
{
int *what_scale;
int i;
what_scale = interval_is_in_major_scale;
if ( !interval_is_in_major_scale[make_0_to_11(abs_i)]
&& interval_is_in_minor_scale[make_0_to_11(abs_i)])
what_scale = interval_is_in_minor_scale;
for (i=0; i<=abs_i; i++) {
if (what_scale[make_0_to_11(i)] || i==abs_i) {
notes[0] = lower_note+i;
play_chord(1,my_snd_chan,notes,shorter_duration/2,1);
}
}
}
break;
case 3: //-- play the lower note
notes[0] = lower_note;
play_chord(1,my_snd_chan,notes,duration1,1);
break;
case 4: //-- compare with another interval
{
DialogPtr my_dialog;
short item_hit;
int interval;
my_dialog = GetNewDialog(SELECT_INTERVAL_MODAL_DLOG_ID,
0,(WindowPtr) -1);
if (VALID_POINTER(my_dialog)) {
ModalDialog(0,&item_hit);
DisposDialog(my_dialog);
interval = item_hit - 1;
if (interval>=0 && interval<=MAX_INTERVAL) {
notes[0] = lower_note;
play_chord(1,my_snd_chan,notes,shorter_duration,1);
notes[0] = lower_note+interval;
play_chord(1,my_snd_chan,notes,shorter_duration,1);
}
}
}
break;
case 5: //-- play inversion
notes[0] = note1;
if (notes[0]==lower_note) notes[0]+=12;
play_chord(1,my_snd_chan,notes,duration1,1);
notes[0] = note2;
if (notes[0]==lower_note) notes[0]+=12;
play_chord(1,my_snd_chan,notes,duration1,1);
break;
case 6: //-- play fifth
notes[0] = lower_note;
play_chord(1,my_snd_chan,notes,shorter_duration,1);
notes[0] = lower_note+7;
play_chord(1,my_snd_chan,notes,shorter_duration,1);
break;
}
}
}
void
choose_interval(int *note1,int *note2,int *duration1,int *duration2,int *rest_between,
int *abs_i,int *lower_note,int *higher_note,
int max_interval,int *interval_enabled,
int mean_note,double typical_tempo,int *shorter_duration)
{
int interval,center,interval1,interval2,min_duration,
max_duration,temp;
double tempo,r1,r2,r3;
do {
interval1 = random_double()*max_interval*1.6;
interval2 = random_double()*max_interval*1.6;
if (interval1<interval2)
interval=interval1;
else
interval=interval2;
while ( random_double()<.5
&& random_double()*max_interval*.3>interval)
++interval;
}while(interval<0 || interval>max_interval || !interval_enabled[interval]);
center = mean_note+(random_double()-.5)*8+(random_double()-.5)*8;
/* mean_note plus or minus an something, biased towards
pitches close to mean_note */
*abs_i = interval;
if (random_double()<.5) interval = -interval;
*note1 = center-interval/2;
*note2 = *note1 + interval;
min_duration = .7 * 2000.*60./typical_tempo;
max_duration = 4 * 2000.*60./typical_tempo;
do {
tempo = typical_tempo*(1.+.2*(random_double()+random_double()-1.));
*duration1 = 2000.*60./tempo;
*duration2 = (*duration1)*small_integer_ratio();
if (random_double()<.5) {
temp = *duration1;
*duration1 = *duration2;
*duration2 = temp;
}
while (*duration1<min_duration || *duration2<min_duration) {
(*duration1) *= 2;
(*duration2) *= 2;
}
while (*duration1>max_duration || *duration2>max_duration) {
(*duration1) /= 2;
(*duration2) /= 2;
}
} while (*duration1>max_duration || *duration2>max_duration
|| *duration1<min_duration || *duration2<min_duration);
*shorter_duration = (*duration1)/2;
while (*shorter_duration<min_duration) {
(*shorter_duration) *= 2;
}
while (*shorter_duration>min_duration*2) {
(*shorter_duration) /= 2;
}
r1 = random_double();
r2 = random_double();
r3 = random_double();
if (r1<.5) {
if (r2<.33)
*rest_between = *duration1;
else {
if (r2<.66)
*rest_between = *duration2;
else {
if (r3<.5)
*rest_between = (*duration1) * small_integer_ratio();
else
*rest_between = (*duration2) * small_integer_ratio();
}
}
}
else
*rest_between = 0;
++ *rest_between; /* always make it slightly staccato */
-- *duration1; /* take the time out of the first note */
if (*note1<*note2) {
*lower_note = *note1;
*higher_note = *note2;
}
else {
*lower_note = *note2;
*higher_note = *note1;
}
}